#!/usr/bin/env bash

source "${rvm_scripts_path}/functions/utility_logging"
source "${rvm_scripts_path}/functions/utility_package"
source "${rvm_scripts_path}/functions/utility_rubygems"
source "${rvm_scripts_path}/functions/utility_system"

__rvm_strings()
{
  \typeset strings ruby_strings

  ruby_strings=($(echo ${rvm_ruby_args:-$rvm_ruby_string}))

  for rvm_ruby_string in "${ruby_strings[@]}" ; do
    strings="$strings $(__rvm_select ; echo $rvm_ruby_string)"
  done

  echo $strings

  return 0
}

# Return a list of directories under a given base path.
# Derived from rvm_ruby_string.
__rvm_ruby_string_paths_under()
{
  \typeset __search_path part parts IFS
  IFS=" "

  __search_path="${1%/}" # Strip off any trailing slash

  if [[ -n "${ZSH_VERSION:-}" ]]
  then parts=(${=rvm_ruby_string//-/ })
  else parts=(${rvm_ruby_string//-/ }) # Strip white space.
  fi

  echo "$__search_path"
  for part in "${parts[@]}"
  do
    __search_path="$__search_path/$part"
    echo "$__search_path"
  done
}

# Strip whitespace and normalize it all.
__rvm_strip()
{
  __rvm_sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e 's/[[:space:]]\{1,\}/ /g'
  return $?
}

# remove all entries from $PATH starting with $1
__rvm_remove_from_path()
{
  export PATH
  \typeset _value
  _value="${1//+(\/)//}"

  # Guard to prevent removal of the entire path
  # https://github.com/rvm/rvm/issues/4759
  if
    [[ $_value == "/*" ]]
  then
    return
  fi

  # remove multiple slashes https://github.com/rvm/rvm/issues/1364
  while [[ "$PATH" == *"//"* ]] ; do PATH="${PATH/\/\///}" ; done
  while [[ "$PATH" == *"/:"* ]] ; do PATH="${PATH/\/:/:}" ; done

  if
    __rvm_string_match ":$PATH:" "*:${_value}:*"
  then
      \typeset -a _path
      _path=()
      __rvm_custom_separated_array _path : "${PATH}"
      __rvm_remove_from_array _path "${_value}" "${_path[@]}"
      __rvm_join_array PATH : _path
  fi
}

__rvm_add_to_path()
{
  export PATH

  if (( $# != 2 )) || [[ -z "$2" ]]
  then
    rvm_error "__rvm_add_to_path requires two parameters"
    return 1
  fi

  __rvm_remove_from_path "$2"
  case "$1" in
    prepend) PATH="$2:$PATH" ;;
    append)  PATH="$PATH:$2" ;;
    #*) anything else will just remove it from PATH - not adding back
  esac

  if
    [[ -n "${rvm_user_path_prefix:-}" ]]
  then
    __rvm_remove_from_path "${rvm_user_path_prefix}"
    PATH="${rvm_user_path_prefix}:$PATH"
  fi
  builtin hash -r
}

rvm_is_a_shell_function()
{
  \typeset _message
  if
    (( ${rvm_is_not_a_shell_function:-0} )) &&
    [[ "${1:-}" != "no_warning" ]]
  then
    if rvm_pretty_print stderr
    then rvm_log "" # newline when error is shown to user
    fi
    if rvm_pretty_print stderr
    then rvm_error "${rvm_notify_clr:-}RVM is not a function, selecting rubies with '${rvm_error_clr:-}rvm use ...${rvm_notify_clr:-}' will not work."
    else rvm_error "RVM is not a function, selecting rubies with 'rvm use ...' will not work."
    fi
    if
      [[ -n "${SUDO_USER:-}" ]]
    then
      rvm_warn '
Please avoid using "sudo" in front of "rvm".
RVM knows when to use "sudo" and will use it only when it is necessary.
'
    else
      rvm_warn '
You need to change your terminal emulator preferences to allow login shell.
Sometimes it is required to use `/bin/bash --login` as the command.
Please visit https://rvm.io/integration/gnome-terminal/ for an example.
'
    fi
  fi
  return ${rvm_is_not_a_shell_function:-0}
}

__rvm_version_sort()
{
  \command \awk -F'[.-]' -v OFS=. '{                   # split on "." and "-", merge back with "."
    original=$0                                        # save original to preserve it before the line is changed
    for (n=1; n<10; n++) {                             # iterate through max 9 components of version
      $n=tolower($n)                                   # ignore case for sorting
      if ($n == "")                 $n="0"             # treat non existing parts as 0
      if ($n ~ /^p[0-9]/)           $n=substr($n, 2)   # old ruby -p notation
      if ($n ~ /^[0-9](rc|b)/)      $n=substr($n, 1, 1)". "substr($n, 2)   # old jruby 0RC1 notation
      if (n == 1 && $n ~ /^[0-9]/)  $n="zzz."$n        # first group must be a string
      if (n > 1 && $n ~ /^[a-z]/)   $n=" "$n           # names go before numbers thanks to space
    }
    print $0"\t"original                               # print the transformed version and original separated by \t
                                                       # so we can extract original after sorting
  }'  \
  | LC_ALL=C \sort -t. -k 1,1d -k 2,2n -k 3,3n -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -k 9,9n \
  | \awk -F'\t' '{print $2}'
}

__rvm_version_compare()
{
  \typeset first

  # first is the lower version number
  first="$( \command \printf "%b" "$1\n$3\n" | __rvm_version_sort | \command \head -n1 )"

  case "$2" in
    (-eq|==|=)
      [[ "$1" == "$3" ]] || return $?
      ;;
    (-ne|!=)
      [[ "$1" != "$3" ]] || return $?
      ;;
    (-gt|\>)
      if [[ "$first" == "head" ]]
      then [[ "$first" == "$1" && "$1" != "$3" ]] || return $?
      else [[ "$first" == "$3" && "$1" != "$3" ]] || return $?
      fi
      ;;
    (-ge|\>=)
      if [[ "$first" == "head" ]]
      then [[ "$first" == "$1" || "$1" == "$3" ]] || return $?
      else [[ "$first" == "$3" || "$1" == "$3" ]] || return $?
      fi
      ;;
    (-lt|\<)
      if [[ "$first" == "head" ]]
      then [[ "$first" == "$3" && "$1" != "$3" ]] || return $?
      else [[ "$first" == "$1" && "$1" != "$3" ]] || return $?
      fi
      ;;
    (-le|\<=)
      if [[ "$first" == "head" ]]
      then [[ "$first" == "$3" || "$1" == "$3" ]] || return $?
      else [[ "$first" == "$1" || "$1" == "$3" ]] || return $?
      fi
      ;;
    (*)
      rvm_error "Unsupported operator '$2'."
      return 1
      ;;
  esac
  return 0
}

# parse comma separated string into an array
# Ex. __rvm_custom_separated_array strings - ruby_string
# adds all elements from `ruby_string` to `strings` array
__rvm_custom_separated_array()
{
  \typeset IFS
  IFS=$2
  if [[ -n "${ZSH_VERSION:-}" ]]
  then eval "$1+=( \${=3} )"
  else eval "$1+=( \$3 )"
  fi
}

__rvm_remove_from_array()
{
  \typeset _array_name _iterator _search
  \typeset -a _temp_array
  _array_name="$1"
  _search="$2"
  shift 2
  _temp_array=()
  for _iterator
  do
    __rvm_string_match "$_iterator" "$_search" || _temp_array+=( "$_iterator" )
  done
  eval "$_array_name=( \"\${_temp_array[@]}\" )"
}

__rvm_join_array()
{
  \typeset IFS
  IFS="$2"
  eval "$1=\"\${$3[*]}\""
}

# take a variable and cut it only to contain only count fields from separator
# Usage: __rvm_take_n variable count separator
__rvm_take_n()
{
  \typeset IFS __temp_counter
  \typeset -a __temp_arr1 __temp_arr2
  IFS=$3
  if [[ -n "${ZSH_VERSION:-}" ]]
  then eval "__temp_arr1=( \${=$1} )"
  else eval "__temp_arr1=( \$$1 )"
  fi
  __temp_counter=0
  __temp_arr2=()
  while (( __temp_counter < $2 ))
  do __temp_arr2+=( "${__temp_arr1[__array_start+__temp_counter++]}" )
  done
  eval "$1=\"\${__temp_arr2[*]}\""
}

__rvm_add_once()
{
  \typeset IFS
  IFS="|"
  eval "[[ \"${IFS}\${${1}[*]}${IFS}\" == \*\"${IFS}\${2}${IFS}\"\* ]] || ${1}+=( \"\${2}\" )"
}

__rvm_find_first_file()
{
  \typeset _first_file _variable_first_file __file_enum
  _first_file=""
  _variable_first_file="$1"
  shift

  for __file_enum in "$@"
  do
    if
      [[ -f "$__file_enum" ]]
    then
      eval "$_variable_first_file=\"\$__file_enum\""
      return 0
    fi
  done
  eval "$_variable_first_file=\"\""
  return 1
}

file_exists_at_url_command()
{
  __rvm_curl --silent --insecure --location --list-only \
    --max-time ${rvm_max_time_flag:-5} --head "$@" 2>&1 |
    __rvm_grep -E 'HTTP/[0-9\.]+ 200' >/dev/null 2>&1 ||
    {
      \typeset __ret=$?
      case ${__ret} in
        (28)
          rvm_warn "RVM was not able to check existence of remote files with timeout of ${rvm_max_time_flag:-3} seconds
you can increase the timeout by setting it in ~/.rvmrc => rvm_max_time_flag=10"
          ;;
      esac
      return ${__ret}
    }
}

file_exists_at_url()
(
  if
    [[ -n "${1:-}" ]]
  then
    unset curl
    file_exists_at_url_command "$1" --insecure ||
    {
      \typeset __ret=$?
      case ${__ret} in
        (60)
          # detect double --insecure and avoid duplication, see:
          # https://github.com/rvm/rvm/issues/2640#issuecomment-35669722
          file_exists_at_url_command "$1" || return $?
          return 0
          ;;
        (*)
          # anything else then 60 just return it
          return ${__ret}
          ;;
      esac
    }
  else
    rvm_warn "Warning: URL was not passed to file_exists_at_url"
    return 1
  fi
)

__rvm_try_sudo()
(
  \typeset -a command_to_run
  \typeset sudo_path sbin_path missing_paths
  command_to_run=( "$@" )
  (( UID == 0 )) ||
  case "$rvm_autolibs_flag_number" in
    (0)
      rvm_debug "Running '$*' would require sudo."
      return 0
      ;;
    (1)
      rvm_warn  "Running '$*' would require sudo."
      return 0
      ;;
    (2)
      rvm_requiremnts_fail error "Running '$*' would require sudo."
      return 1
      ;;
    (*)
      if
        is_a_function __rvm_sudo
      then
        missing_paths=""
        for sbin_path in /sbin /usr/sbin /usr/local/sbin
        do
          if [[ -d "${sbin_path}" ]] && [[ ":$PATH:" != *":${sbin_path}:"* ]]
          then missing_paths+=":${sbin_path}"
          fi
        done
        if [[ -n "${missing_paths}" ]]
        then command_to_run=( /usr/bin/env PATH="${PATH}${missing_paths}" "${command_to_run[@]}" )
        fi
        command_to_run=( __rvm_sudo -p "%p password required for '$*': " "${command_to_run[@]}" )
      else
        rvm_error "Running '$*' would require sudo, but 'sudo' is not found!"
        return 1
      fi
      ;;
  esac
  "${command_to_run[@]}" || return $?
)

__rvm_run_wrapper()
( # ( = subprocess
  file="$1"
  action="${2:-}"
  shift 2
  rubies_string="${1:-}"
  args=( $@ )
  source "$rvm_scripts_path"/base
  source "$rvm_scripts_path"/$file
)

__rvm_calculate_space_free()
{
  # OpenBSD does not have 'df -m' param
  __free_space="$( \command \df -Pk "$1" | __rvm_awk 'BEGIN{x=4} /Free/{x=3} $3=="Avail"{x=3} END{print $x}' )"
  if [[ "${__free_space}" == *M ]]
  then __free_space="${__free_space%M}" # some systems ignore -k and print M
  else __free_space="$(( __free_space / 1024 ))"
  fi
}

__rvm_calculate_space_used()
{
  __used_space="$( \command \du -msc "$@" | __rvm_awk 'END {print $1}' )"
  __used_space="${__used_space%M}"
}

__rvm_require()
{
  [[ -f "$1" ]] && source "$1"
}
